package cn.fzkj.helper;

import cn.fzkj.config.OssProperties;
import cn.fzkj.file.FilePathDescriptor;
import cn.fzkj.model.UploadResult;
import io.minio.*;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import java.util.Objects;
import java.util.Optional;

/**
 * @author mr
 * @description
 * @since 2024/4/30
 */
public class MinioHelper implements FileHelper {

    private final Logger log = LoggerFactory.getLogger(MinioHelper.class);

    private final OssProperties.MinioConf minioConf;

    public MinioHelper(OssProperties.MinioConf minioConf) {
        this.minioConf = minioConf;
    }

    @NotNull
    @Override
    public UploadResult upload(@NotNull MultipartFile file) {
        MinioClient client = client();
        String bucketName = minioConf.getNonNullBucketName();
        try {
            createBucket(client, bucketName);
            FilePathDescriptor pathDescriptor = new FilePathDescriptor.Builder()
                    .setBasePath(minioConf.getHttpsUrl() + bucketName)
                    .setSubPath(minioConf.getNonNullSource())
                    .setAutomaticRename(true)
                    .setRenamePredicate(predicate -> true)
                    .setOriginalName(file.getOriginalFilename())
                    .build();

            PutObjectArgs args = PutObjectArgs.builder()
                    .contentType(file.getContentType())
                    .bucket(bucketName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .object(pathDescriptor.getRelativePath())
                    .build();
            client.ignoreCertCheck();
            client.putObject(args);

            UploadResult uploadResult = new UploadResult();
            uploadResult.setFilePath(pathDescriptor.getFullPath());
            uploadResult.setFileName(pathDescriptor.getName());
            uploadResult.setKey(pathDescriptor.getRelativePath());
            uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
            uploadResult.setSize(file.getSize());
            uploadResult.setSuffix(pathDescriptor.getExtension());

            handleImageMetadata(file, uploadResult, pathDescriptor::getFullPath);
            return uploadResult;
        } catch (Exception e) {
            log.error("upload file to minio failed, file: {}", file.getOriginalFilename(), e);
            throw new RuntimeException("上传文件到minio失败，file: " + file.getOriginalFilename());
        }
    }

    @Override
    public void delete(@NotNull String key) {
        MinioClient client = client();
        String bucketName = minioConf.getNonNullBucketName();

        try {
            client.ignoreCertCheck();
            RemoveObjectArgs args = RemoveObjectArgs.builder().bucket(bucketName).object(key).build();
            client.removeObject(args);
        } catch (Exception e) {
            log.error("delete file from minio failed, key: {}", key, e);
            throw new RuntimeException("从minio删除文件失败，key: " + key);
        }
    }

    private MinioClient client() {
        String endpoint = Optional.ofNullable(minioConf.getEndpoint()).orElseThrow(() -> new IllegalArgumentException("minio endpoint can not be null."));
        String accessKey = minioConf.getNonNullAccessKey();
        String secretKey = minioConf.getNonNullSecretKey();
        String region = minioConf.getNonNullRegion();
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .region(region)
                .build();
    }

    private void createBucket(MinioClient client, String bucketName) throws Exception {
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            MakeBucketArgs args = MakeBucketArgs.builder().bucket(bucketName).objectLock(false).build();
            client.makeBucket(args);
            // 设置桶为公共
            String sb = "{\"Version\":\"2012-10-17\"," +
                    "\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":" +
                    "{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"," +
                    "\"s3:GetBucketLocation\"],\"Resource\":[\"arn:aws:s3:::" + bucketName +
                    "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\"],\"Resource\":[\"arn:aws:s3:::" +
                    bucketName +
                    "/*\"]}]}";
            client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(sb).build());
        }
    }
}
